package com.example.config.shiro;

import com.example.bean.shiro.SysUserEntity;
import com.example.service.shiro.SysUserService;
import com.example.util.shiro.RedisUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.List;
import java.util.Set;

/**
 * @application:
 * @author: LiYuhang
 * @Date: 2021/7/26 10:00
 * @version: 0.1
 * @Description :
 * @Modified By:
 */
public class ShiroRealm  extends AuthorizingRealm {
    private static final Logger log = LoggerFactory.getLogger(ShiroRealm.class);

    private static  final String REDIS_KEY__USER_TOKEN_PERFIX="PREFIX_USER_TOKEN_";

    @Autowired
    @Lazy
    private SysUserService sysUserService;

    @Autowired
    @Lazy
    private RedisUtil redisUtil;


    /**
     * 权限信息认证(包括角色以及权限)是用户访问controller的时候才进行验证(redis存储的此处权限信息)
     * 触发检测用户权限时才会调用此方法，例如checkRole,checkPermission
     *
     * @param principals 身份信息
     * @return AuthorizationInfo 权限信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        log.info("===============Shiro权限认证开始============ [ roles、permissions]==========");
        String username = null;
        if (principals != null) {
            SysUserEntity sysUser = (SysUserEntity) principals.getPrimaryPrincipal();
            username = sysUser.getUsername();
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 设置用户拥有的角色集合，比如“admin,test”
        Set<String> roleSet = sysUserService.getUserRolesSet(username);
        info.setRoles(roleSet);
        // 设置用户拥有的权限集合，比如“sys:role:add,sys:user:add”
        List<String> permissionSet = sysUserService.getUserPermissionsSet(username);
        info.addStringPermissions(permissionSet);
        log.info("===============Shiro权限认证成功==============");
        return info;
    }


    /**
     * 处理登陆
     * @param auth
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) auth;
        String username = token.getUsername();
        if (username == null) {
            throw new AuthenticationException("username为空!");
        }
        log.debug("———校验token是否有效————checkUserTokenIsEffect——————— "+ token);
        SysUserEntity loginUser = sysUserService.getUserByName(username);
        if (loginUser == null) {
            throw new AuthenticationException("用户不存在!");
        }
        // 判断用户状态
        if (loginUser.getStatus() != 1) {
            throw new AuthenticationException("账号已被锁定,请联系管理员!");
        }
        Md5Hash md5Hash=new Md5Hash(new String(token.getPassword()),loginUser.getSalt(),2);
        log.info("md5Hash:{} loggin result:{}",md5Hash,md5Hash.toString().equalsIgnoreCase(loginUser.getPassword()));
        return new SimpleAuthenticationInfo(loginUser, loginUser.getPassword(),ByteSource.Util.bytes(loginUser.getSalt()), getName());
    }
    public void clearAuthz() {
        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }
}
